package com.duojuhe.coremodule.chat.im.service.impl;

import com.duojuhe.common.constant.DataScopeConstants;
import com.duojuhe.common.enums.SystemEnum;
import com.duojuhe.common.exception.base.DuoJuHeException;
import com.duojuhe.coremodule.chat.im.entity.ChatGroup;
import com.duojuhe.coremodule.chat.im.entity.ChatUsersChatList;
import com.duojuhe.coremodule.chat.im.entity.ChatUsersFriends;
import com.duojuhe.coremodule.chat.im.mapper.ChatGroupMapper;
import com.duojuhe.coremodule.chat.im.mapper.ChatUsersChatListMapper;
import com.duojuhe.coremodule.chat.im.mapper.ChatUsersFriendsMapper;
import com.duojuhe.coremodule.chat.im.pojo.dto.chatlist.*;
import com.duojuhe.coremodule.chat.im.service.ChatUsersChatListService;
import com.duojuhe.websocket.EventCodes;
import com.duojuhe.websocket.socket.SocketSessionCache;
import com.duojuhe.common.annotation.DataScopeFilter;
import com.duojuhe.common.annotation.KeyLock;
import com.duojuhe.common.bean.UserTokenInfoVo;
import com.duojuhe.common.enums.chat.ImChatEnum;
import com.duojuhe.common.result.ErrorCodes;
import com.duojuhe.common.result.PageResult;
import com.duojuhe.common.result.ServiceResult;
import com.duojuhe.common.utils.encryption.md5.MD5Util;
import com.duojuhe.common.utils.page.PageHelperUtil;
import com.duojuhe.coremodule.BaseService;
import com.duojuhe.coremodule.system.entity.SystemUser;
import com.duojuhe.coremodule.system.mapper.SystemUserMapper;
import com.duojuhe.websocket.subscriber.SendChatSubscribeUtil;
import com.duojuhe.websocket.subscriber.SubscribeHandleDto;
import com.duojuhe.websocket.subscriber.message.sendmsg.MessageUntreatedDto;
import com.duojuhe.websocket.subscriber.message.sendmsg.SystemSendMessageDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class ChatUsersChatListServiceImpl extends BaseService implements ChatUsersChatListService {
    @Resource
    private SendChatSubscribeUtil sendChatSubscribeUtil;
    @Resource
    private ChatUsersChatListMapper chatUsersChatListMapper;
    @Resource
    private ChatUsersFriendsMapper chatUsersFriendsMapper;
    @Resource
    private ChatGroupMapper chatGroupMapper;
    @Resource
    private SystemUserMapper systemUserMapper;

    /**
     * 统计当前用户多聊未读消息数量
     * @return
     */
    @Override
    public ServiceResult<Integer> queryCountMyUnreadChatMessageNum() {
        //统计未读多聊数量
        Integer chatMessageNum = chatUsersChatListMapper.queryCountUntreatedChatMessageByUserId(getCurrentLoginUserId());
        return ServiceResult.ok(chatMessageNum);
    }

    /**
     * 【用户会话列表查询】分页查询用户会话列表查询
     *
     * @param req
     * @return
     */
    @DataScopeFilter(dataScope = DataScopeConstants.SELF_DATA)
    @Override
    public ServiceResult<PageResult<List<QueryMyChatUsersChatListPageRes>>> queryMyChatUsersChatListPageResList(QueryMyChatUsersChatListPageReq req) {
        PageHelperUtil.orderByAndStartPage(req, "updateTime desc,sort desc, id desc");
        List<QueryMyChatUsersChatListPageRes> list = chatUsersChatListMapper.queryMyChatUsersChatListPageResList(req);
        list.forEach(this::setHandleMyChatUsersChatListPageRes);
        return PageHelperUtil.returnServiceResult(req, list);
    }


    /**
     * 聊天列表创建服务接口
     *
     * @param req
     * @return
     */
    @KeyLock(lockKeyParts = "saveChatUsersChatList", fixedKey = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult saveChatUsersChatList(SaveChatUsersChatListReq req) {
        //当前登录人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //当前用户id
        String userId = userTokenInfoVo.getUserId();
        //接收人id
        String receiverId = req.getReceiverId();
        //聊天类型
        Integer talkType = req.getTalkType();
        //构建用户或群组基础信息对象
        ChatUsersGroupInfoRes infoRes = buildChatUsersGroupInfoRes(talkType,userId,receiverId);
        //否标识
        Integer no = ImChatEnum.IM_YES_NO.NO.getKey();
        //当前时间
        Date nowDate = new Date();
        //插入会员主动方向的聊天会话
        buildFormCreateUserChatList(userId, receiverId, nowDate, talkType);
        //插入会员被动方向的聊天会话
        buildToCreateUserChatList(receiverId, userId, nowDate, talkType);
        //构建返回值对象
        QueryMyChatUsersChatListPageRes res = new QueryMyChatUsersChatListPageRes();
        res.setId(infoRes.getChatListId());
        res.setTalkType(talkType);
        res.setUserId(userId);
        res.setReceiverId(receiverId);
        res.setUpdateTime(nowDate);
        res.setIsDelete(no);
        res.setIsDisturb(no);
        res.setIsTop(no);
        res.setIsOnline(ImChatEnum.IM_YES_NO.YES.getKey());
        res.setHeadPortrait(infoRes.getHeadPortrait());
        res.setRealName(infoRes.getRealName());
        res.setUnreadNum(0);
        res.setFriendRemark(infoRes.getFriendRemark());
        return ServiceResult.ok(res);
    }



    /**
     * 设置会话是否置顶
     *
     * @param req
     * @return
     */
    @Override
    public ServiceResult setTopChatUsersChatListById(ChatUsersChatListIdReq req) {
        ChatUsersChatList chatUsersChatListOld = chatUsersChatListMapper.selectByPrimaryKey(req.getId());
        if (chatUsersChatListOld == null) {
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        Integer isTop = ImChatEnum.IM_YES_NO.NO.getKey();
        if (isTop.equals(chatUsersChatListOld.getIsTop())) {
            isTop = ImChatEnum.IM_YES_NO.YES.getKey();
        }
        ChatUsersChatList usersChatList = new ChatUsersChatList();
        usersChatList.setId(req.getId());
        usersChatList.setIsTop(isTop);
        chatUsersChatListMapper.updateByPrimaryKeySelective(usersChatList);
        return ServiceResult.ok(ErrorCodes.SUCCESS);
    }

    /**
     * 设置会话免打扰
     *
     * @param req
     * @return
     */
    @Override
    public ServiceResult setDisturbChatUsersChatList(SetDisturbChatUsersChatListReq req) {
        //当前登录人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //主键ID 当前用户id和接收id的MD5值
        String id = MD5Util.getMD532(userTokenInfoVo.getUserId() + req.getReceiverId());
        ChatUsersChatList chatUsersChatListOld = chatUsersChatListMapper.selectByPrimaryKey(id);
        if (chatUsersChatListOld == null || !req.getTalkType().equals(chatUsersChatListOld.getTalkType())) {
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        if (!chatUsersChatListOld.getIsDisturb().equals(req.getIsDisturb())) {
            ChatUsersChatList usersChatList = new ChatUsersChatList();
            usersChatList.setId(chatUsersChatListOld.getId());
            usersChatList.setIsDisturb(req.getIsDisturb());
            chatUsersChatListMapper.updateByPrimaryKeySelective(usersChatList);
        }
        return ServiceResult.ok(ErrorCodes.SUCCESS);
    }

    /**
     * 设置会话删除
     *
     * @param req
     * @return
     */
    @Override
    public ServiceResult deleteChatUsersChatListById(ChatUsersChatListIdReq req) {
        ChatUsersChatList chatUsersChatListOld = chatUsersChatListMapper.selectByPrimaryKey(req.getId());
        if (chatUsersChatListOld == null) {
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        Integer isDelete = ImChatEnum.IM_YES_NO.NO.getKey();
        if (isDelete.equals(chatUsersChatListOld.getIsDelete())) {
            isDelete = ImChatEnum.IM_YES_NO.YES.getKey();
        }
        ChatUsersChatList usersChatList = new ChatUsersChatList();
        usersChatList.setId(req.getId());
        usersChatList.setIsDelete(isDelete);
        usersChatList.setDeleteTime(new Date());
        chatUsersChatListMapper.updateByPrimaryKeySelective(usersChatList);
        return ServiceResult.ok(ErrorCodes.SUCCESS);
    }

    /**
     * 清除未读数量 清除聊天消息未读数服务接口
     *
     * @param req
     * @return
     */
    @Override
    public ServiceResult clearUnreadNumChatUsersChatList(ClearUnreadNumChatUsersChatListReq req) {
        //当前用户id
        String userId = getCurrentLoginUserId();
        //主键ID 当前用户id和接收id的MD5值
        String id = MD5Util.getMD532(userId + req.getReceiverId());
        ChatUsersChatList usersChatList = new ChatUsersChatList();
        usersChatList.setId(id);
        usersChatList.setUnreadNum(0);
        chatUsersChatListMapper.updateByPrimaryKeySelective(usersChatList);
        //推送消息
        handleSystemMessageUntreatedNum(userId);
        return ServiceResult.ok(ErrorCodes.SUCCESS);
    }


    /**
     * 处理用户未读消息数量发送
     * @param userId
     */
    private void handleSystemMessageUntreatedNum(String userId){
        try {
            if (StringUtils.isBlank(userId)){
                return;
            }
            //多聊未读消息
            Integer chatMessageNum = chatUsersChatListMapper.queryCountUntreatedChatMessageByUserId(userId);
            //构建消息对象
            String type = SystemEnum.UNTREATED_TYPE.UNTREATED_CHAT_MESSAGE.getKey();
            SystemSendMessageDto sendMessageDto = new SystemSendMessageDto(userId,new MessageUntreatedDto(chatMessageNum,type));
            // 异步发送消息
            SubscribeHandleDto<SystemSendMessageDto> subscribeHandleDto = new SubscribeHandleDto<SystemSendMessageDto>();
            subscribeHandleDto.setEventType(EventCodes.EVENT_SYSTEM_MESSAGE.getEvent());
            subscribeHandleDto.setMessageData(sendMessageDto);
            sendChatSubscribeUtil.sendSystemSubscribeMessage(subscribeHandleDto);
        }catch (Exception e){
            log.error("【发送用户未读多聊消息总数出现异常】,用户ID:{}",userId,e);
        }
    }


    /**
     * 创建主动方向用户会话列表
     *
     * @param userId
     * @param receiverId
     * @param nowDate
     * @param talkType
     */
    private void buildFormCreateUserChatList(String userId, String receiverId, Date nowDate, Integer talkType) {
        //否标识
        Integer no = ImChatEnum.IM_YES_NO.NO.getKey();
        //主键ID 当前用户id和接收id的MD5值
        String id = MD5Util.getMD532(userId + receiverId);
        //查询会话记录
        ChatUsersChatList chatList = chatUsersChatListMapper.selectByPrimaryKey(id);
        //构建新的聊天会话
        ChatUsersChatList chatUsersChatList = new ChatUsersChatList();
        chatUsersChatList.setId(id);
        chatUsersChatList.setTalkType(talkType);
        chatUsersChatList.setUserId(userId);
        chatUsersChatList.setReceiverId(receiverId);
        chatUsersChatList.setUpdateTime(nowDate);
        chatUsersChatList.setUnreadNum(0);
        chatUsersChatList.setSort(0);
        chatUsersChatList.setIsDelete(no);
        chatUsersChatList.setDeleteTime(nowDate);
        if (chatList == null) {
            //不存在则创建
            chatUsersChatList.setIsDisturb(no);
            chatUsersChatList.setIsTop(no);
            chatUsersChatList.setIsRobot(no);
            chatUsersChatList.setLastReleaseTime(nowDate);
            chatUsersChatList.setCreateUserId(userId);
            chatUsersChatList.setCreateTime(nowDate);
            chatUsersChatListMapper.insertSelective(chatUsersChatList);
        } else {
            if (!no.equals(chatList.getIsDelete())){
                chatUsersChatList.setLastReleaseTime(nowDate);
            }
            chatUsersChatListMapper.updateByPrimaryKeySelective(chatUsersChatList);
        }
    }


    /**
     * 创建被动方向用户会话列表
     *
     * @param userId
     * @param receiverId
     * @param nowDate
     * @param talkType
     */
    private void buildToCreateUserChatList(String userId, String receiverId, Date nowDate, Integer talkType) {
        //否标识
        Integer no = ImChatEnum.IM_YES_NO.NO.getKey();
        //主键ID 当前用户id和接收id的MD5值
        String id = MD5Util.getMD532(userId + receiverId);
        //查询会话记录
        ChatUsersChatList chatList = chatUsersChatListMapper.selectByPrimaryKey(id);
        //构建新的聊天会话
        ChatUsersChatList chatUsersChatList = new ChatUsersChatList();
        chatUsersChatList.setId(id);
        chatUsersChatList.setTalkType(talkType);
        chatUsersChatList.setUserId(userId);
        chatUsersChatList.setReceiverId(receiverId);
        if (chatList == null) {
            //不存在则创建
            chatUsersChatList.setIsDelete(no);
            chatUsersChatList.setDeleteTime(nowDate);
            chatUsersChatList.setUnreadNum(0);
            chatUsersChatList.setSort(0);
            chatUsersChatList.setUpdateTime(nowDate);
            chatUsersChatList.setIsDisturb(no);
            chatUsersChatList.setIsTop(no);
            chatUsersChatList.setIsRobot(no);
            chatUsersChatList.setLastReleaseTime(nowDate);
            chatUsersChatList.setCreateUserId(userId);
            chatUsersChatList.setCreateTime(nowDate);
            chatUsersChatListMapper.insertSelective(chatUsersChatList);
        } else {
            if (!no.equals(chatList.getIsDelete())){
                chatUsersChatList.setIsDelete(no);
                chatUsersChatList.setDeleteTime(nowDate);
                chatUsersChatList.setUpdateTime(nowDate);
                chatUsersChatList.setUnreadNum(0);
                chatUsersChatList.setSort(0);
                chatUsersChatList.setLastReleaseTime(nowDate);
            }
            chatUsersChatListMapper.updateByPrimaryKeySelective(chatUsersChatList);
        }
    }

    /**
     * 处理返回值的数据
     *
     * @param res
     */
    private void setHandleMyChatUsersChatListPageRes(QueryMyChatUsersChatListPageRes res) {
        if (res == null) {
            return;
        }
        if (ImChatEnum.TalkType.GROUP_CHAT.getKey().equals(res.getTalkType())) {
            return;
        }
        //是在线标识
        Integer onlineYes = ImChatEnum.IM_YES_NO.YES.getKey();
        //不在线标识
        Integer onlineNo = ImChatEnum.IM_YES_NO.NO.getKey();
        //判断是否该显示最后聊天记录
        Date lastReleaseTime = res.getLastReleaseTime();
        //更新时间
        Date updateTime = res.getUpdateTime();
        if (updateTime.getTime() > lastReleaseTime.getTime()) {
            res.setMsgText("");
        }
        res.setIsOnline(SocketSessionCache.checkSocketSessionUserIsOnlineByUserId(res.getReceiverId()) ? onlineYes : onlineNo);
        res.setFriendRemark(getFriendRemark(res.getUserId(), res.getReceiverId()));
    }


    /**
     * 构建用户或者群组的基本信息
     * @param talkType
     * @param userId
     * @param receiverId
     * @return
     */
    private ChatUsersGroupInfoRes buildChatUsersGroupInfoRes(Integer talkType,String userId,String receiverId){
        ChatUsersGroupInfoRes res = new ChatUsersGroupInfoRes();
        //好友备注名
        String friendRemark = "";
        //真实姓名
        String realName = "";
        //头像
        String headPortrait = "";
        //主键ID 当前用户id和接收id的MD5值
        String id = MD5Util.getMD532(userId + receiverId);
        //判断类型
        if (ImChatEnum.TalkType.PRIVATE_CHAT.getKey().equals(talkType)) {
            SystemUser systemUser = systemUserMapper.selectByPrimaryKey(receiverId);
            if (systemUser == null) {
                throw new DuoJuHeException(ErrorCodes.NOT_FRIENDS_NO_TALK_ERROR);
            }
            ChatUsersFriends friends = chatUsersFriendsMapper.selectByPrimaryKey(id);
            if (friends == null) {
                throw new DuoJuHeException(ErrorCodes.NOT_FRIENDS_NO_TALK_ERROR);
            }
            //真实姓名
            realName = systemUser.getRealName();
            //头像
            headPortrait = systemUser.getHeadPortrait();
            //好友备注名
            friendRemark = friends.getFriendRemark();
        } else {
            ChatGroup group = chatGroupMapper.selectByPrimaryKey(receiverId);
            if (group == null) {
                throw new DuoJuHeException(ErrorCodes.NOT_GROUP_USER_NO_TALK_ERROR);
            }
            //真实姓名
            realName = group.getGroupName();
            //头像
            headPortrait = group.getGroupAvatar();
        }
        res.setChatListId(id);
        res.setRealName(realName);
        res.setHeadPortrait(headPortrait);
        res.setFriendRemark(friendRemark);
        return res;
    }

    /**
     * 获取好友备注
     *
     * @param userId
     * @param receiverId
     * @return
     */
    private String getFriendRemark(String userId, String receiverId) {
        //主键ID 当前用户id和好友id的MD5值
        String friendsUid = MD5Util.getMD532(userId + receiverId);
        ChatUsersFriends usersFriends = chatUsersFriendsMapper.selectByPrimaryKey(friendsUid);
        if (usersFriends == null) {
            return "";
        }
        return usersFriends.getFriendRemark();
    }

}
